import Snake from "./Snake"
import Rect from "../base/Rect"
import Chunk from "../world/Chunk"
import Food from "../world/Food"
import Config from "../config/Config"
import { Util } from "../util/Util"
import SnakeNode from "./SnakeNode"

const util = Util

/** 玩家蛇类 */
export default class PlayerSnake extends Snake {

    /** 可见屏幕 */
    private _screen: Rect
    /** 可见屏幕区块 */
    private _screenChunks: Chunk[]

    /** 生成 */
    spawn() {
        super.spawn()
    }

    /** 每帧执行 */
    update() {
        if (!this.isDeath) {
            this._screen = null
            this._screenChunks = null
        }
        super.update()
    }

    /** 移动后执行 */
    updateAfterMove() {
        super.updateAfterMove()
    }

    /** 控制角度 */
    ctrlTurn(ang: number) {
        this._head.toAng = ang
    }

    /** 控制加速 */
    ctrlSprint(isSprint: boolean) {
        this._head.isSprint = isSprint
    }


    /** 更新屏幕 */
    private updateScreen() {
        if (!this._screen) {
            this._screen = new Rect(this._head).setSize(Config.view.screen)
        }
    }

    /** 更新屏幕区块 */
    private updateScreenChunks() {
        if (!this.screenChunks) {
            this.updateScreen()
            this._screenChunks = this.world.getChunks(this._screen)
        }
    }

    /** 更新可见食物映射 */
    updateScreenFoodMap(foodSet: Set<number>): {
        /** 加载食物集合 */
        loadFoods: Food[],
        /** 卸载食物集合 */
        unloadFoodMap: Map<number, number>
    } {
        this.updateScreenChunks()

        let loadFoods: Food[] = []
        //<食物id,吃食物的蛇节点id>
        let unloadFoodMap = new Map<number, number>()
        foodSet.forEach(foodId => unloadFoodMap.set(foodId, 0))

        this.world.getFoods(this._screenChunks).forEach(food => {
            //从卸载集合中移除 剩下的就是待卸载的
            unloadFoodMap.delete(food.id)
            if (!foodSet.has(food.id)) {
                //待加载的
                loadFoods.push(food)
                foodSet.add(food.id)
            }
        })
        let eatenFoodMap = this.world.extractEatenFoodMap()
        unloadFoodMap.forEach((_, foodId) => {
            foodSet.delete(foodId)
            let eaterId = eatenFoodMap.get(foodId)
            if (eaterId) {
                unloadFoodMap.set(foodId, eaterId)
            }
        })

        return { loadFoods, unloadFoodMap }
    }

    /** 更新可见蛇节点映射 */
    updateScreenNodeMap(nodeSet: Set<number>): {
        /** 加载蛇节点映射 <蛇节点id,蛇节点> */
        loadNodeMap: Map<Snake, SnakeNode[]>,
        /** 卸载蛇节点集合 */
        unloadNodeIdSet: Set<number>
    } {
        this.updateScreenChunks()

        let loadNodeMap = this.getScreenSnakeNodeMap()
        let unloadNodeIdSet = new Set(nodeSet)

        loadNodeMap.forEach(nodes => {
            nodes.forEach(node => {
                //从已有中去除，剩下的就是待卸载的
                unloadNodeIdSet.delete(node.id)
                //待加载的
                nodeSet.add(node.id)
            })
        })
        unloadNodeIdSet.forEach(nodeId => nodeSet.delete(nodeId))

        return { loadNodeMap, unloadNodeIdSet }
    }

    /** 更新已加载蛇映射 */
    updateLoadedSnakeMap(snakeSet: Set<number>): {
        /** 加载蛇集合 */
        loadSnakes: Snake[],
        /** 卸载蛇集合 */
        unloadSnakeIdSet: Set<number>
    } {
        let loadSnakes: Snake[] = []
        let unloadSnakeIdSet = new Set(snakeSet)

        this.world.snakeMap.forEach((snake, snakeId) => {
            //从已有中去除，剩下的就是待卸载的
            unloadSnakeIdSet.delete(snakeId)
            if (!snakeSet.has(snakeId)) {
                //待加载的
                loadSnakes.push(snake)
                snakeSet.add(snakeId)
            }
        })
        unloadSnakeIdSet.forEach(snakeId => snakeSet.delete(snakeId))

        return { loadSnakes, unloadSnakeIdSet }
    }


    // ================================================================

    /** 屏幕 */
    get screen() { return this._screen }

    /** 屏幕区块 */
    get screenChunks() { return this._screenChunks }

    /** 获取屏幕区块的蛇节点映射 */
    getScreenSnakeNodeMap() {
        return this.world.getSnakeNodeMap(this.screenChunks)
    }

    /** 获取屏幕区块自己的蛇节点映射 */
    getSelfScreenSnakeNodeMap() {
        return this.world.getSnakeNodeMapInclude(this.screenChunks, [this])
    }

    /** 获取屏幕区块其他蛇的蛇节点映射 */
    getOtherScreenSnakeNodeMap() {
        return this.world.getSnakeNodeMapExclude(this.screenChunks, [this])
    }

}